import React, { Component, cloneElement, Children } from 'react';
import PropTypes from 'prop-types';

import './Navigator.css';



/* 
# Sole
为内容创建带有唯一标识符的对象；

该对象有以下属性：
key : number    //唯一标识符，每次创建都不一样，即使用相同的值初创建也是如此；
value : any     //创建该对象时传的值
*/
class Sole {
    constructor(value) {
        this.value = value;
        let currentDate = new Date();
        this.key = currentDate.getTime() + Math.random();
    }
}




/* 
# NavConfiger
设置 Navigator 的桥梁；

在子组件的 context 中 注入了以下方法；

- 为使用者提供的方法：
   pushNavConfig : (navConfig)-> configId      //往导航条配置栈中推入一个导航条的配置对象 navConfig，并返回配置id，该 id 可用于通过 popNavConfig 方法推出该 id  对应的配置对象；
   popNavConfig : (configId)->void     //从导航条配置栈中推出 configId 对应的配置对象；configId 是 执行 pushNavConfig 方法的返回值；

- 为 Navigator 提供的方法：
   pushNavigator : (navigator)-> navID      //往导航条栈中推入一个 Navigator 实例，并返回一个 navID
   popNavigator : (navID)->void        //从导航条栈中推出 navID 对应的 Navigator 实例

*/
class NavConfiger extends Component {

    static childContextTypes = {
        pushNavConfig: PropTypes.func,
        popNavConfig: PropTypes.func,
        pushNavigator: PropTypes.func,
        popNavigator: PropTypes.func
    };


    navSoleList = [];

    constructor(props) {
        super(props);

        this.pushNavigator = this.pushNavigator.bind(this);
        this.popNavigator = this.popNavigator.bind(this);

        this.pushNavConfig = this.pushNavConfig.bind(this);
        this.popNavConfig = this.popNavConfig.bind(this);
    }


    getChildContext() {

        return {
            pushNavConfig: this.pushNavConfig,
            popNavConfig: this.popNavConfig,

            pushNavigator: this.pushNavigator,
            popNavigator: this.popNavigator
        };
    }


    get currentNavSole() {
        let navSoleList = this.navSoleList;
        let soleCount = navSoleList.length;
        let currentIndex = soleCount - 1;
        let currentSole = navSoleList[currentIndex];

        if (!currentSole) {
            throw new Error("没有找到 Navigator 实例；请确保在 Navigator 实例创建之后，再执行与 Navigator 相关的操作！");
        }

        return currentSole;
    }


    pushNavigator(navigator) {
        let navSole = new Sole(navigator);
        this.navSoleList.push(navSole);
        // this.forceUpdate();

        return navSole.key;
    }

    popNavigator(navID) {
        let navSoleList = this.navSoleList;
        let deleIndex = navSoleList.findIndex(function (sole) {
            return sole.key == navID;
        });
        this.navSoleList.splice(deleIndex, 1);
        // this.forceUpdate();
    }




    pushNavConfig(navConfig) {
        let currentNavSole = this.currentNavSole;
        let currentNav = currentNavSole.value;
        let configKey = currentNav.pushNavConfig(navConfig);

        let configID = {
            navKey: currentNavSole.key,
            configKey: configKey
        }

        return configID;
    }

    popNavConfig(configID) {
        let navKey = configID.navKey;

        let navSoleList = this.navSoleList;
        let navSole = navSoleList.find(function (sole) {
            return sole.key == navKey;
        });

        if (navSole) {
            let nav = navSole.value;
            nav.popNavConfig(configID.configKey);
        }
    }





    render() {
        return this.props.children;
    }
}







/* 
# Navigator 导航条

## props
navConfig ：{
    hide ?: boolean,    // 设置是否显示 导航条
    left ?: string || element,      //设置leftItem 
    center ?: string || element,    //设置centerItem
    right: ?: string || element,    //设置rightItem
    leftAction ?: function,      //设置 leftItem 的 click 事件处理函数
    rightAction ?: function,    //设置 rightItem 的 click 事件处理函数
    navClass ?: string,         //设置 navArea 的 css 类
    leftAreaClass ?: string,    //设置 leftArea 的 css 类
    centerAreaClass ?: string,  //设置 centerClass 的 css 类
    rightAreaClass ?: string,   //设置 rightArea 的 csss 类
}       //配置导航条

## 其它 prop
Navigator 会把其它的 props 设置到 Navigator 的根元素上，即: navArea ; 所以，给 Navigator 设置 以下 prop 会直接设置在 navArea 上；

className ?: string    //设置 navArea 的 css 类
style ?: StyleObject    //设置 navArea 的内联样式对象


*/
class Navigator extends Component {


    static contextTypes = {
        pushNavigator: PropTypes.func,
        popNavigator: PropTypes.func
    };


    navConfigSoleList = [];
    navID;

    defaultNavConfig = {
        left: (<p className="left_item" onClick={this.backClickHandle} ></p>)
    };

    get currentNavConfig() {
        let navConfigSoleList = this.navConfigSoleList;
        let currentSole = navConfigSoleList[navConfigSoleList.length - 1];
        return (currentSole && currentSole.value) || this.props.navConfig;
    }


    constructor(props) {
        super(props);
        this.backClickHandle = this.backClickHandle.bind(this);
    }

    componentWillMount() {
        this.navID = this.context.pushNavigator(this);
    }

    componentWillUnmount() {
        this.context.popNavigator(this.navID);
    }




    pushNavConfig(navConfig) {
        let navConfigSole = new Sole(navConfig);
        this.navConfigSoleList.push(navConfigSole);
        this.forceUpdate();

        return navConfigSole.key;
    }

    popNavConfig(configKey) {
        let navConfigSoleList = this.navConfigSoleList;
        let deleIndex = navConfigSoleList.findIndex(function (sole) {
            return sole.key == configKey;
        });

        if (deleIndex < 0) {
            throw new Error("没有找到 navConfig ；你可能过度执行 popNavConfig 方法 或者 没有给 popNavConfig 方法传入正确的 configID，请确保操作 popNavConfig 与 pushNavConfig 一一 对应 ！");
        }

        this.navConfigSoleList.splice(deleIndex, 1);
        this.forceUpdate();
    }

    backClickHandle() {
        window.history.back();
    }

    get finalNavConfig() {
        return this.currentNavConfig || this.defaultNavConfig;
    }

    passNavItems(navConfig) {

        let { left, center, right, leftAction = this.backClickHandle, rightAction } = navConfig;

        let leftItem = left;
        let centerItem = this.passCenterItem(center);
        let rightItem = right;

        if (left && typeof left == "string") {

            leftItem = <p className="left_item" onClick={leftAction} >{left}</p>;

        }


        if (right && typeof right == "string") {

            rightItem = <p className="right_item" onClick={rightAction} >{right}</p>;

        }


        return { left: leftItem, center: centerItem, right: rightItem };


    }


    passCenterItem(centerConfig) {

        let centerItem = centerConfig;

        if (centerConfig && typeof centerConfig == "string") {

            centerItem = <p className="center_item">{centerConfig}</p>;

        }

        return centerItem;
    }








    render() {

        let { children, className, style,navConfig, ...otherProps } = this.props;
        let currentNavConfig = this.currentNavConfig;
        let finalNavConfig = this.finalNavConfig;




        let childCount = Children.count(children);

        let leftItem = null;
        let centerItem = null;
        let rightItem = null;



        switch (childCount) {
            case 1: return cloneElement(children, { navConfig: currentNavConfig });

            case 3: {

                let navItems = Children.map(children, function (element, index) {

                    switch (index) {
                        case 0: return cloneElement(element, { navConfig: currentNavConfig });
                        case 1: return cloneElement(element, { navConfig: currentNavConfig });
                        case 2: return cloneElement(element, { navConfig: currentNavConfig });
                    }

                });

                leftItem = navItems[0];
                centerItem = navItems[1];
                rightItem = navItems[2];

                break;
            }


            case 2: {

                let navItems = Children.map(children, function (element, index) {

                    switch (index) {
                        case 0: return cloneElement(element, { navConfig: currentNavConfig });
                        case 1: return cloneElement(element, { navConfig: currentNavConfig });
                    }

                });

                let centerConfig = currentNavConfig && currentNavConfig.center;

                leftItem = navItems[0];
                centerItem = this.passCenterItem(centerConfig);
                rightItem = navItems[1];

                break
            }



            default: {
                let navItems = this.passNavItems(finalNavConfig);
                leftItem = navItems.left;
                centerItem = navItems.center;
                rightItem = navItems.right;

            }

        }



        let { navClass, leftAreaClass, centerAreaClass, rightAreaClass, hide } = finalNavConfig;

        let rootClass = `navigator ${className} ${navClass}`;

        let rootDisplay = hide ? { display: "none" } : {};
        let rootStyle = { ...style, ...rootDisplay };

        return (
            <div className={rootClass} style={rootStyle}  {...otherProps} >
                <div className={`left ${leftAreaClass}`} >{leftItem}</div>
                <div className={`center ${centerAreaClass}`} >{centerItem}</div>
                <div className={`right  ${rightAreaClass}`} >{rightItem}</div>
            </div>
        );

    }




}



export { NavConfiger, Navigator, Sole };